<template>
  <section class="jee-image-upload-container">
    <div class="desc" v-if="getImageDesc">{{getImageDesc}}</div>
    <!-- 上传区 -->
    <div class="upload-wrap" :class="{'single-mode': file.imageUrl}">
      <el-upload
        ref="upload"
        class="z-image-uploader jee-hover-border"
        action=""
        :accept="getAccept"
        :show-file-list="false"
        :before-upload="beforeImageUpload"
        :on-change="handleChange"
        :auto-upload="false"
      >
        <div class="text-wrap">
          <jee-icon :iconClass="iconClass"></jee-icon>
          <div class="text" v-if="title">{{title}}</div>
          <div class="text" v-if="getImageSize">{{getImageSize}}</div>
        </div>
      </el-upload>
      <!-- 上传后的样式 -->
      <div class="image-wrap" v-if="file.imageUrl">
        <div class="image">
          <img :src="file.imageUrl" :style="{width: width || 'auto', height: height || 'auto'}">
        </div>
        <div class="img-editor-wrap">
          <jee-icon iconClass="guanbi" class="guanbi jee-hover-fill" @click="handleRemove"/>
          <div class="editor jee-hover-border-important">
            <el-tooltip content="重新上传" placement="bottom" effect="light">
              <jee-icon iconClass="chongxinshangchuan" class="jee-hover-fill" @click="reUpload"/>
            </el-tooltip>
            <el-tooltip content="查看大图" placement="bottom" effect="light">
              <jee-icon iconClass="chakandatu" class="jee-hover-fill"
              @click="handlePreview"/>
            </el-tooltip>
            <el-tooltip content="裁剪" placement="bottom" effect="light">
              <jee-icon iconClass="caijian" class="jee-hover-fill"
              @click="handleCropper"/>
            </el-tooltip>
          </div>
        </div>
      </div>
    </div>
    <!-- 进度条 -->
    <el-progress :stroke-width='2' :percentage="percentage" v-if="percentage>0 && percentage <=100" style="maxWidth: 414px"></el-progress>
    <!-- 说明文字 -->
    <div class="z-tip-form-item" v-if="tip">{{tip}}</div>
    <!-- 放大 -->
    <el-dialog :visible.sync="dialogVisible"
    custom-class="transparent"
      class="image-preview-dialog "
      append-to-body >
      <img class="t-img" :src="file.imageUrl" alt="">
    </el-dialog>
    <!-- 裁剪 -->
    <el-dialog class="cropper-dialog" title="图片裁剪" :visible.sync="dialogVisible2" append-to-body>
      <div class="cropper-content">
        <div class="cropper-wrap">
          <vueCropper
            ref="cropper"
            :img="file.imageUrl"
            :info="option.info"
            :full="option.full"
            :outputSize="option.outputSize"
            :outputType="suffix"
            :canMove="option.canMove"
            :canMoveBox="option.canMoveBox"
            :centerBox="option.centerBox"
            :fixedBox="option.fixedBox"
            :fixed="fixed"
            :original="option.original"
            :autoCrop="option.autoCrop"
            :autoCropWidth="option.autoCropWidth"
            :autoCropHeight="option.autoCropHeight"
            :high="option.high"
            @realTime="realTime"
          />
        </div>
        <div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px'}">
          <div :style="previews.div">
            <img :src="previews.url" :style="previews.img">
          </div>
        </div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button size="small" @click="dialogVisible2 = false">取 消</el-button>
        <el-button size="small" type="primary" @click="handleSubmit" :loading="loading">确认</el-button>
      </div>
    </el-dialog>
  </section>
</template>
<script>
import { VueCropper } from 'vue-cropper'
import { getImgToBase64 } from '@/utils'

export default {
  name: 'JeeImageUpload',
  props: {
    value: {
      validator (value) {
        return true
      }
    },
    uploadOption: {
      type: Object,
      default: () => ({})
    },
    imgType: {
      type: String,
      default: ''
    },
    autoUpload: {
      type: Boolean,
      default: true
    },
    fixed: {
      type: Boolean,
      default: false
    },
    desc: {
      type: String,
      default: ''
    },
    tip: {
      type: String,
      default: ''
    },
    title: {
      type: String,
      default: '点击上传图片'
    },
    iconClass: {
      type: String,
      default: 'shangchuantupian'
    },
    width: {
      type: [Number, String],
      default: 0
    },
    height: {
      type: [Number, String],
      default: 0
    },
    type: {
      type: [Array, String],
      default: () => []
    },
    size: {
      type: [String, Number],
      default: ''
    },
    unit: {
      type: String,
      default: ''
    },
    defaultFileName: {
      type: String,
      default: ''
    },
    defaultUrl: {
      type: String,
      default: ''
    },
    limit: {
      type: [String, Number],
      default: ''
    }
  },
  components: {
    VueCropper
  },
  data () {
    return {
      dialogVisible: false,
      dialogVisible2: false,
      loading: false,
      file: {},
      suffix:'png',
      option: {
        autoCropWidth: this.width || 100,
        autoCropHeight: this.height || 100,
        info: true, // 裁剪框的大小信息
        outputSize: 1, // 裁剪生成图片的质量
        outputType: 'png', // 输出图片格式
        canScale: true, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        fixedBox: false, // 固定截图框大小 不允许改变
        fixed: false, // 是否开启截图框宽高固定比例
        full: false, // 是否输出原图比例的截图
        canMove: true, // 能否拖动图片
        canMoveBox: true, // 截图框能否拖动
        original: false, // 上传图片按照原始比例渲染
        centerBox: false, // 截图框是否被限制在图片里面
        high: true // 是否根据dpr生成适合屏幕的高清图片
      },
      previews: {},
      percentage: 0,
      imageStyle: {}
    }
  },
  computed: {
    getImageDesc () {
      if (this.desc) return this.desc
      const allowType = this.type instanceof Array ? this.type.join(', ') : this.type
      let desc = allowType ? `支持 ${allowType} 图片格式` : ''
      if (Number(this.size) && this.unit) desc = desc + ` (文件大小不超过${this.size}${this.unit})`
      return desc
    },
    getImageSize () {
      return this.width && this.height ? `建议${this.width} * ${this.height}PX` : ''
    },
    getAccept () {
      const allowTypes = this.type instanceof Array ? this.type : (this.type ? this.type.split(',') : [])
      return allowTypes.length ? allowTypes.map(t => `image/${t}`).join(',') : 'image/*'
    }
  },
  watch: {
    value (newVal) {
      if (!newVal) {
        this.file = {}
      }
      if (typeof newVal === 'object') {
        this.initData()
      }
    },
    defaultUrl (newVal, oldVal) {
      if (newVal !== oldVal) {
        this.initData()
      }
    }
  },
  methods: {
    // 获取图片宽高
    getImageStyle () {
      const url = this.file.imageUrl
      if (url) {
        const that = this
        var img = new Image()
        img.src = url
        img.onload = function () {
          that.imageStyle = {
            width: img.width + 'px',
            height: img.height + 'px',
            w: img.width,
            h: img.height
          }
        }
      }
    },
    // 点击放大查看
    handlePreview () {
      this.dialogVisible = true
    },
    // 点击裁剪
    handleCropper () {
      this.dialogVisible2 = true
    },
    // 重新上传
    reUpload () {
      this.$refs.upload.$refs['upload-inner'].$refs.input.click()
      // document.querySelector('.jee-image-upload-container .el-upload input').click()
    },
    // 上传-文件类型
    uploadType (file) {
      var type = file.raw.type
      var i = type.indexOf('/')
      var suffix = type.slice(0, i).toLowerCase()
      this.suffix = type.slice(i+1).toLowerCase();

      var fileType = ''
      // File文件 Flash Flash Image图片 Media视频 Audio音频 为空则默认Image
      switch (suffix) {
        case 'image':
          fileType = ''
          break
        case 'text':
          fileType = 'File'
          break
        case 'application':
          fileType = 'File'
          break
        case 'video':
          fileType = 'Media'
          break
        case 'audio':
          fileType = 'Audio'
          break
        default:
          fileType = ''
          break
      }
      return fileType
    },
    // 上传-选择文件
    handleChange (file, fileList) {
      if (!this.beforeImageUpload(file)) return
      this.file = {
        file: file,
        fileName: this.defaultFileName || file.name,
        fileType: this.uploadType(file),
        imageUrl: URL.createObjectURL(file.raw)
      }

      this.getImageStyle()
      this.handleUpload()
    },
    // 上传到服务器
    handleUpload () {
      const param = new FormData() // 创建form对象
      param.append('uploadFile', this.file.file.raw, this.file.fileName) // 通过append向form对象添加数据
      if (this.autoUpload) {
        // param.append('spaceId', this.id)
        param.append('typeStr', this.file.fileType)
        param.append('addToRes', true)
        if (this.modeObj) {
          param.append('modelId', this.modeObj.modelId || '')
          param.append('fieldName', this.modeObj.fieldName)
        }
        // 修复水印图片在上传时被添加水印
        if(this.uploadOption.mark === false){
          param.append('mark', false)
        }
        const that = this
        const onUploadProgress = function (e) {
          // 属性lengthComputable主要表明总共需要完成的工作量和已经完成的工作是否可以被测量
          // 如果lengthComputable为false，就获取不到e.total和e.loaded
          if (e.lengthComputable) {
            var rate = e.loaded / e.total // 已上传的比例
            if (rate < 1) {
              that.percentage = Number((rate * 100).toFixed(0))
            // 这里的进度只能表明文件已经上传到后台，但是后台有没有处理完还不知道
            // 因此不能直接显示为100%，不然用户会误以为已经上传完毕，关掉浏览器的话就可能导致上传失败
            } else {
              that.percentage = 100
            }
          }
        }
        this.$request.fetchUpload(param, onUploadProgress).then(res => {
          if (res.code === 200) {
            that.$message({
              message: '上传成功',
              type: 'success'
            })
            that.$emit('input', res.data.resourceId)
            that.$emit('getUrl', res.data, that.imgType)
          } else {
            that.handleRemove()
          }
          that.percentage = 0
        })
      } else {
        this.$emit('input', param)
        this.$emit('getUrl', this.file, this.imgType)
      }
    },
    // 移除
    handleRemove () {
      this.$emit('input', '')
      this.file = {}
      this.$emit('getUrl', {}, this.imgType)
    },
    // 上传到页面前进行检查
    beforeImageUpload (file) {
      // 判断文件类型 windows下accept无效
      let isJPG = true
      var i = file.name.lastIndexOf('.')
      var suffix = file.name.substring(i + 1).toLowerCase()
       this.suffix = file.name.substring(i + 1).toLowerCase();

      const allowTypes = this.type instanceof Array ? this.type : (this.type ? this.type.split(',') : [])

      if (allowTypes.length) {
        isJPG = allowTypes.includes(suffix)
      }
      // 判断文件大小
      let isLt2M = true
      if (Number(this.size)) {
        const allowSize = this.unit === 'MB' ? (1024 * 1024) : 1024
        isLt2M = file.size / allowSize < Number(this.size)
      }
      // 提示错误信息
      if (!isJPG) {
        this.$message.error(`上传图片只能是 ${allowTypes.join(',')} 格式!`)
      }
      if (!isLt2M) {
        this.$message.error(`上传图片大小不能超过 ${this.size}${this.unit || 'KB'}!`)
      }
      return isJPG && isLt2M
    },
    // 实时预览函数
    realTime (data) {
      this.previews = data
    },
    // 获取截图数据
    handleSubmit () {
      this.$refs.cropper.getCropBlob((data) => {
        let files = new File([data], this.file.fileName, { type: 'image/png', lastModified: Date.now() })
        this.file.file = { raw: files }
        this.file.imageUrl = URL.createObjectURL(data)
        this.dialogVisible2 = false
        this.handleUpload()
      })
    },
    initData () {
      if (!this.autoUpload) {
        return
      }
      // 传单图路径，转为图片数据
      const that = this
      const getDefaultFile = function (dataUrl) {
        that.$set(that.file, 'imageUrl', dataUrl)
      }
      if (this.defaultUrl) {
        getImgToBase64(this.$getPath(this.defaultUrl), getDefaultFile)
      } else {
        this.file = {}
      }
      // 传单图对象，返回id
      if (this.value && typeof this.value === 'object') {
        this.$emit('input', this.value.id || '')
        this.$emit('getUrl', {}, this.imgType)
      }
    }
  },
  mounted () {
    this.initData()
  }
}
</script>
<style lang="scss">
.jee-image-upload-container{
  .desc{
    color: #B3B3B3;
    font-size: 12px;
    line-height: 1.5;
    padding-top: 11px;
    padding-bottom: 17px;
  }
  .upload-wrap{
    display: flex;
    flex-wrap: wrap;
    .image-wrap{
      position: relative;
      margin-left: 20px;
      margin-bottom: 20px;
      .img-editor-wrap{
        position: absolute;
        top: 0;
        left: 0;
        width: 140px;
        height: 140px;
        overflow: hidden;
        background-color: rgba(0,0,0,0.7);
        border-radius: 4px;
        opacity: 0;
        &:hover{
          opacity: 1;
        }
        .guanbi{
          position: absolute;
          top: 8px;
          right: 8px;
          font-size: 18px;
          fill: #ffffff;
        }
        .editor{
          display: flex;
          justify-content: space-between;
          align-items: center;
          width: 140px;
          height: 40px;
          position: absolute;
          bottom: 0;
          padding: 0 16px;
          box-sizing: border-box;
          background-color: #ffffff;
          border-radius: 0 0 4px 4px;
          border: 1px dashed #E2E2E2;
          .jee-svg-icon{
            font-size: 22px;
            fill: #B3B3B3;
            cursor: pointer;
          }
        }
      }
      .image {
        width: 140px;
        height: 140px;
        background-color: #f0f0f0;
        display: flex;
        align-items: center;
        border-radius: 4px;
        overflow: hidden;
        img{
          max-width: 100%;
          max-height: 100%;
          display: block;
          margin: 0 auto;
        }
      }
    }
    &.single-mode {
      .z-image-uploader{
        visibility: hidden;
        position: absolute;
      }
      .image-wrap{
        margin: 0;
      }
    }
  }
}
.el-dialog{
  .el-dialog__body{
    .cropper-dialog{
      .cropper-content {
        .cropper-wrap {
          width: 100%;
          height: 300px;
        }
        .show-preview{
          border: 1px solid #e8e8e8;
          margin-top: 20px;
          overflow: hidden;
        }
      }
    }
  }
}
</style>
